import * as Cesium from 'cesium';

export class ModelManager {
  constructor(cesiumManager) {
    this.cesiumManager = cesiumManager;
    this.models = new Map(); // 存储所有模型实体
    this.modelCollections = new Map(); // 存储模型集合
  }

  /**
   * 加载3D模型
   * @param {String} id - 模型ID
   * @param {Object} position - 模型位置 {longitude, latitude, height}
   * @param {String} modelUrl - 模型文件URL
   * @param {Object} options - 模型选项
   * @returns {Entity} 模型实体
   */
  addModel(id, position, modelUrl, options = {}) {
    if (!this.cesiumManager || !this.cesiumManager.viewer) {
      throw new Error('Cesium manager or viewer is not initialized');
    }

    const defaultOptions = {
      scale: 1.0,
      minimumPixelSize: 128,
      maximumScale: 20000,
      color: Cesium.Color.WHITE,
      colorBlendMode: Cesium.ColorBlendMode.HIGHLIGHT,
      shadows: Cesium.ShadowMode.ENABLED,
      heading: 0,
      pitch: 0,
      roll: 0
    };

    const modelOptions = Object.assign({}, defaultOptions, options);

    // 计算模型的方向
    const hpr = new Cesium.HeadingPitchRoll(
      Cesium.Math.toRadians(modelOptions.heading),
      Cesium.Math.toRadians(modelOptions.pitch),
      Cesium.Math.toRadians(modelOptions.roll)
    );
    
    const orientation = Cesium.Transforms.headingPitchRollQuaternion(
      Cesium.Cartesian3.fromDegrees(position.longitude, position.latitude, position.height || 0),
      hpr
    );

    const entity = this.cesiumManager.viewer.entities.add({
      id: id,
      name: id,
      position: Cesium.Cartesian3.fromDegrees(position.longitude, position.latitude, position.height || 0),
      orientation: orientation,
      model: {
        uri: modelUrl,
        scale: modelOptions.scale,
        minimumPixelSize: modelOptions.minimumPixelSize,
        maximumScale: modelOptions.maximumScale,
        color: modelOptions.color,
        colorBlendMode: modelOptions.colorBlendMode,
        shadows: modelOptions.shadows
      }
    });

    this.models.set(id, entity);
    return entity;
  }

  /**
   * 批量加载模型
   * @param {Array} modelConfigs - 模型配置数组
   * @returns {Array} 模型实体数组
   */
  addModels(modelConfigs) {
    const entities = [];
    modelConfigs.forEach(config => {
      const entity = this.addModel(
        config.id,
        config.position,
        config.modelUrl,
        config.options
      );
      entities.push(entity);
    });
    return entities;
  }

  /**
   * 创建模型集合
   * @param {String} collectionId - 集合ID
   * @param {Array} modelConfigs - 模型配置数组
   * @returns {Array} 模型实体数组
   */
  createModelCollection(collectionId, modelConfigs) {
    const entities = this.addModels(modelConfigs);
    this.modelCollections.set(collectionId, entities);
    return entities;
  }

  /**
   * 获取模型
   * @param {String} id - 模型ID
   * @returns {Entity} 模型实体
   */
  getModel(id) {
    return this.models.get(id);
  }

  /**
   * 获取模型集合
   * @param {String} collectionId - 集合ID
   * @returns {Array} 模型实体数组
   */
  getModelCollection(collectionId) {
    return this.modelCollections.get(collectionId);
  }

  /**
   * 更新模型属性
   * @param {String} id - 模型ID
   * @param {Object} options - 更新选项
   */
  updateModel(id, options) {
    const entity = this.models.get(id);
    if (!entity) {
      throw new Error(`Model with id "${id}" not found`);
    }

    if (options.position) {
      entity.position = Cesium.Cartesian3.fromDegrees(
        options.position.longitude,
        options.position.latitude,
        options.position.height || 0
      );
    }

    if (options.orientation) {
      const hpr = new Cesium.HeadingPitchRoll(
        Cesium.Math.toRadians(options.orientation.heading || 0),
        Cesium.Math.toRadians(options.orientation.pitch || 0),
        Cesium.Math.toRadians(options.orientation.roll || 0)
      );
      
      entity.orientation = Cesium.Transforms.headingPitchRollQuaternion(
        entity.position.getValue(),
        hpr
      );
    }

    if (options.model && entity.model) {
      Object.assign(entity.model, options.model);
    }
  }

  /**
   * 设置模型可见性
   * @param {String} id - 模型ID
   * @param {Boolean} show - 是否显示
   */
  setModelVisibility(id, show) {
    const entity = this.models.get(id);
    if (entity && entity.model) {
      entity.model.show = show;
    }
  }

  /**
   * 批量设置模型可见性
   * @param {Array} ids - 模型ID数组
   * @param {Boolean} show - 是否显示
   */
  setModelsVisibility(ids, show) {
    ids.forEach(id => this.setModelVisibility(id, show));
  }

  /**
   * 设置模型集合可见性
   * @param {String} collectionId - 集合ID
   * @param {Boolean} show - 是否显示
   */
  setModelCollectionVisibility(collectionId, show) {
    const collection = this.modelCollections.get(collectionId);
    if (collection) {
      collection.forEach(entity => {
        if (entity.model) {
          entity.model.show = show;
        }
      });
    }
  }

  /**
   * 缩放模型
   * @param {String} id - 模型ID
   * @param {Number} scale - 缩放比例
   */
  scaleModel(id, scale) {
    const entity = this.models.get(id);
    if (entity && entity.model) {
      entity.model.scale = scale;
    }
  }

  /**
   * 为模型添加动画效果
   * @param {String} id - 模型ID
   * @param {Object} animationOptions - 动画选项
   * @returns {Function} 停止动画的函数
   */
  animateModel(id, animationOptions = {}) {
    const entity = this.models.get(id);
    if (!entity) {
      throw new Error(`Model with id "${id}" not found`);
    }

    const defaultOptions = {
      rotationAxis: 'z', // x, y, z
      rotationSpeed: 0.01,
      bounce: false,
      bounceHeight: 10,
      bounceSpeed: 0.02
    };

    const options = Object.assign({}, defaultOptions, animationOptions);
    
    // 保存原始位置
    const originalPosition = Cesium.Cartesian3.clone(entity.position.getValue());
    let animationActive = true;
    let rotationAngle = 0;
    let bounceOffset = 0;
    let bounceDirection = 1;

    const animate = () => {
      if (!animationActive || !entity.position) return;
      
      // 旋转动画
      if (options.rotationAxis) {
        rotationAngle += options.rotationSpeed;
        const hpr = new Cesium.HeadingPitchRoll(
          options.rotationAxis === 'z' ? rotationAngle : 0,
          options.rotationAxis === 'y' ? rotationAngle : 0,
          options.rotationAxis === 'x' ? rotationAngle : 0
        );
        
        entity.orientation = Cesium.Transforms.headingPitchRollQuaternion(
          entity.position.getValue(),
          hpr
        );
      }
      
      // 弹跳动画
      if (options.bounce) {
        bounceOffset += options.bounceSpeed * bounceDirection;
        if (bounceOffset > options.bounceHeight || bounceOffset < 0) {
          bounceDirection *= -1;
        }
        
        const newPosition = Cesium.Cartesian3.clone(originalPosition);
        newPosition.z += bounceOffset;
        entity.position = newPosition;
      }
      
      requestAnimationFrame(animate);
    };
    
    animate();
    
    // 返回停止函数
    return () => {
      animationActive = false;
    };
  }

  /**
   * 使模型面向相机
   * @param {String} id - 模型ID
   * @param {Boolean} enable - 是否启用
   */
  setModelBillboard(id, enable) {
    const entity = this.models.get(id);
    if (!entity) return;
    
    if (enable) {
      // 保存原始方向
      entity._originalOrientation = entity.orientation;
      // 设置为始终面向相机
      entity.orientation = new Cesium.VelocityOrientationProperty(entity.position);
    } else {
      // 恢复原始方向
      if (entity._originalOrientation) {
        entity.orientation = entity._originalOrientation;
        delete entity._originalOrientation;
      }
    }
  }

  /**
   * 高亮模型
   * @param {String} id - 模型ID
   * @param {Object} highlightOptions - 高亮选项
   */
  highlightModel(id, highlightOptions = {}) {
    const entity = this.models.get(id);
    if (!entity || !entity.model) return;

    const defaultHighlight = {
      color: Cesium.Color.YELLOW.withAlpha(0.5),
      blendMode: Cesium.ColorBlendMode.MIX
    };

    const options = Object.assign({}, defaultHighlight, highlightOptions);

    // 保存原始颜色和混合模式
    if (!entity._originalModelProperties) {
      entity._originalModelProperties = {
        color: entity.model.color?.getValue() || entity.model.color,
        colorBlendMode: entity.model.colorBlendMode
      };
    }

    entity.model.color = options.color;
    entity.model.colorBlendMode = options.blendMode;
  }

  /**
   * 取消模型高亮
   * @param {String} id - 模型ID
   */
  unhighlightModel(id) {
    const entity = this.models.get(id);
    if (!entity || !entity.model || !entity._originalModelProperties) return;

    entity.model.color = entity._originalModelProperties.color;
    entity.model.colorBlendMode = entity._originalModelProperties.colorBlendMode;
    
    delete entity._originalModelProperties;
  }

  /**
   * 克隆模型
   * @param {String} originalId - 原始模型ID
   * @param {String} newId - 新模型ID
   * @param {Object} newPosition - 新位置 {longitude, latitude, height}
   * @returns {Entity} 新模型实体
   */
  cloneModel(originalId, newId, newPosition) {
    const originalEntity = this.models.get(originalId);
    if (!originalEntity || !originalEntity.model) {
      throw new Error(`Model with id "${originalId}" not found`);
    }

    // 获取原始模型属性
    const model = originalEntity.model;
    const position = originalEntity.position.getValue();
    const cartographic = Cesium.Cartographic.fromCartesian(position);
    
    const entity = this.cesiumManager.viewer.entities.add({
      id: newId,
      name: newId,
      position: Cesium.Cartesian3.fromDegrees(
        newPosition.longitude, 
        newPosition.latitude, 
        newPosition.height || cartographic.height
      ),
      model: {
        uri: model.uri?.getValue() || model.uri,
        scale: model.scale?.getValue() || model.scale,
        minimumPixelSize: model.minimumPixelSize?.getValue() || model.minimumPixelSize,
        maximumScale: model.maximumScale?.getValue() || model.maximumScale,
        color: model.color?.getValue() || model.color,
        colorBlendMode: model.colorBlendMode,
        shadows: model.shadows
      }
    });

    this.models.set(newId, entity);
    return entity;
  }

  /**
   * 计算模型边界框
   * @param {String} id - 模型ID
   * @returns {Object} 边界框信息
   */
  getModelBoundingSphere(id) {
    const entity = this.models.get(id);
    if (!entity || !entity.model) {
      throw new Error(`Model with id "${id}" not found`);
    }

    return entity.model.boundingSphere;
  }

  /**
   * 相机聚焦到模型
   * @param {String} id - 模型ID
   * @param {Object} options - 聚焦选项
   * @returns {Promise} 聚焦完成的Promise
   */
  focusOnModel(id, options = {}) {
    const entity = this.models.get(id);
    if (!entity) {
      throw new Error(`Model with id "${id}" not found`);
    }

    return new Promise((resolve) => {
      if (!this.cesiumManager || !this.cesiumManager.viewer) {
        resolve();
        return;
      }

      const defaultOptions = {
        duration: 2.0,
        offset: new Cesium.HeadingPitchRange(
          Cesium.Math.toRadians(0),
          Cesium.Math.toRadians(-30),
          1000
        )
      };

      const focusOptions = Object.assign({}, defaultOptions, options);

      this.cesiumManager.viewer.flyTo(entity, {
        duration: focusOptions.duration,
        offset: focusOptions.offset,
        complete: () => resolve(),
        cancel: () => resolve()
      });
    });
  }

  /**
   * 移除模型
   * @param {String} id - 模型ID
   */
  removeModel(id) {
    const entity = this.models.get(id);
    if (entity) {
      this.cesiumManager.viewer.entities.remove(entity);
      this.models.delete(id);
    }
  }

  /**
   * 移除模型集合
   * @param {String} collectionId - 集合ID
   */
  removeModelCollection(collectionId) {
    const collection = this.modelCollections.get(collectionId);
    if (collection) {
      collection.forEach(entity => {
        this.cesiumManager.viewer.entities.remove(entity);
      });
      this.modelCollections.delete(collectionId);
    }
  }

  /**
   * 清除所有模型
   */
  clearAllModels() {
    this.models.forEach((entity, id) => {
      this.cesiumManager.viewer.entities.remove(entity);
    });
    this.models.clear();
    this.modelCollections.clear();
  }

  /**
   * 获取所有模型
   * @returns {Map} 所有模型
   */
  getAllModels() {
    return this.models;
  }

  /**
   * 获取模型数量
   * @returns {Number} 模型数量
   */
  getModelCount() {
    return this.models.size;
  }
}